home *** CD-ROM | disk | FTP | other *** search
/ Internet Info 1994 March / Internet Info CD-ROM (Walnut Creek) (March 1994).iso / networking / appletalk / uab.shar / snitp.c < prev    next >
C/C++ Source or Header  |  1990-07-12  |  9KB  |  408 lines

  1. static char rcsid[] = "$Author: cck $ $Date: 88/09/14 10:20:35 $";
  2. static char rcsident[] = "$Header: /src/local/mac/cap/etalk/RCS/snitp.c,v 1.9 88/09/14 10:20:35 cck Rel $";
  3. static char revision[] = "$Revision: 1.9 $";
  4.  
  5. /*
  6.  * snitp.c - Simple "protocol" level interface to Streams based NIT
  7.  * (SunOS 4.0)
  8.  *
  9.  *  Provides ability to read/write packets at ethernet level
  10.  *
  11.  *
  12.  * Copyright (c) 1988 by The Trustees of Columbia University 
  13.  *  in the City of New York.
  14.  *
  15.  * Permission is granted to any individual or institution to use,
  16.  * copy, or redistribute this software so long as it is not sold for
  17.  * profit, provided that this notice and the original copyright
  18.  * notices are retained.  Columbia University nor the author make no
  19.  * representations about the suitability of this software for any
  20.  * purpose.  It is provided "as is" without express or implied
  21.  * warranty.
  22.  *
  23.  * Edit History:
  24.  *
  25.  *  July 1988  CCKim Created
  26.  *
  27. */
  28.  
  29. static char columbia_copyright[] = "Copyright (c) 1988 by The Trustees of \
  30. Columbia University in the City of New York";
  31.  
  32. #include <stdio.h>
  33. #include <sys/types.h>
  34. #include <sys/time.h>
  35. #include <sys/ioctl.h>
  36. #include <sys/file.h>
  37. #include <sys/socket.h>
  38. #include <sys/uio.h>
  39. #include <net/if.h>
  40. #include <net/nit.h>
  41. #include <net/nit_if.h>
  42. #include <net/nit_pf.h>
  43. #include <net/nit_buf.h>
  44. #include <net/packetfilt.h>
  45. #include <stropts.h>
  46. #include <netinet/in.h>
  47. #include <netinet/if_ether.h>
  48. #include <netdb.h>
  49. #include <ctype.h>
  50.  
  51. #include <netat/appletalk.h>
  52. #include "proto_intf.h"
  53.  
  54. typedef struct ephandle {    /* ethernet protocol driver handle */
  55.   int inuse;            /* true if inuse */
  56.   int socket;            /* file descriptor of socket */
  57.   struct ifreq ifr;
  58.   int protocol;            /* ethernet protocol */
  59. } EPHANDLE;
  60.  
  61. private inited = FALSE;
  62.  
  63. private EPHANDLE ephlist[MAXOPENPROT];
  64.  
  65.  
  66. /*
  67.  * setup for particular device devno
  68.  * all pi_open's will go this device
  69. */
  70. export
  71. pi_setup()
  72. {
  73.   int i;
  74.  
  75.   if (!inited) {
  76.     for (i = 0 ; i < MAXOPENPROT; i++)
  77.       ephlist[i].inuse = FALSE;
  78.     (void)init_fdlistening();
  79.     inited = TRUE;        /* don't forget now */
  80.   }
  81.   return(TRUE);
  82. }
  83.  
  84. /*
  85.  * Open up a protocol handle:
  86.  *   user level data:
  87.  *      file descriptor
  88.  *      protocol
  89.  * 
  90.  *   returns -1 and ephandle == NULL if memory allocation problems
  91.  *   returns -1 for other errors
  92.  *   return edx > 0 for okay
  93. */
  94. export int
  95. pi_open(protocol, dev, devno)
  96. int protocol;
  97. char *dev;
  98. int devno;
  99. {
  100.   struct ephandle *eph;
  101.   char devnamebuf[100];        /* room for device name */
  102.   int s;
  103.   int i;
  104.  
  105.   for (i = 0; i < MAXOPENPROT; i++) {
  106.     if (!ephlist[i].inuse)
  107.       break;
  108.   }
  109.   if (i == MAXOPENPROT)
  110.     return(0);            /* nothing */
  111.   eph = &ephlist[i];        /* find handle */
  112.  
  113.   sprintf(devnamebuf, "%s%d",dev,devno);
  114.   strncpy(eph->ifr.ifr_name, devnamebuf, sizeof eph->ifr.ifr_name);
  115.   eph->ifr.ifr_name[sizeof eph->ifr.ifr_name - 1] = ' ';
  116.  
  117.   if ((s = init_nit(1024, protocol, &eph->ifr)) < 0) {
  118.     return(-1);
  119.   }
  120.  
  121.   eph->inuse = TRUE;
  122.   eph->socket = s;
  123.   eph->protocol = protocol;
  124.   return(i+1);            /* skip zero */
  125. }
  126.  
  127. /* returns TRUE if machine will see own broadcasts */
  128. export int
  129. pi_delivers_self_broadcasts()
  130. {
  131.   return(FALSE);
  132. }
  133.  
  134. export int
  135. pi_close(edx)
  136. int edx;
  137. {
  138.   if (edx < 1 || edx > MAXOPENPROT || !ephlist[edx-1].inuse)
  139.     return(-1);
  140.   fdunlisten(ephlist[edx-1].socket); /* toss listener */
  141.   close(ephlist[edx-1].socket);
  142.   ephlist[edx-1].inuse = 0;
  143.   return(0);
  144. }
  145.  
  146. /*
  147.  * Initialize nit on a particular protocol type
  148.  * 
  149.  * Runs in promiscous mode for now.
  150.  *
  151.  * Return: socket if no error, < 0 o.w.
  152. */
  153. private int
  154. init_nit(chunksize, protocol, ifr)
  155. u_long chunksize;
  156. u_short protocol;
  157. struct ifreq *ifr;
  158. {
  159.   u_long if_flags;
  160.   struct strioctl si;
  161.   int s;
  162.   
  163.   /* get clone */
  164.   if ((s = open("/dev/nit", O_RDWR)) < 0) {
  165.     perror("open: /dev/nit");
  166.     return(-1);
  167.   }
  168.   
  169.   /* set up messages */
  170.   if (ioctl(s, I_SRDOPT, (char *)RMSGD) < 0) { /* want messages */
  171.     perror("ioctl: discretem");
  172.     return(-1);
  173.   }
  174.   
  175.   si.ic_timout = INFTIM;
  176.   
  177.   if (setup_pf(s, protocol) < 0)
  178.     return(-1);
  179. #define NOBUF
  180. #ifndef NOBUF
  181.   setup_buf(s, chunksize);
  182. #endif  
  183.   /* bind */
  184.   si.ic_cmd = NIOCBIND;        /* bind */
  185.   si.ic_timout = 10;
  186.   si.ic_len = sizeof(*ifr);
  187.   si.ic_dp = (caddr_t)ifr;
  188.   if (ioctl(s, I_STR, (caddr_t)&si) < 0) {
  189.     perror(ifr->ifr_name);
  190.     return(-1);
  191.   }
  192.   
  193.   /* flush read queue */
  194.   ioctl(s, I_FLUSH, (char *)FLUSHR);
  195.   return(s);
  196. }
  197.  
  198. #ifndef NOBUF
  199. /*
  200.  * setup buffering (not wanted)
  201.  *
  202. */
  203. setup_buf(s, chunksize)
  204. int s;
  205. u_long chunksize;
  206. {
  207.   struct strioctl si;
  208.   struct timeval timeout;
  209.  
  210.   /* Push and configure the buffering module. */
  211.   if (ioctl(s, I_PUSH, "nbuf") < 0) {
  212.     perror("ioctl: nbuf");
  213.   }
  214.   timeout.tv_sec = 0;
  215.   timeout.tv_usec = 200;
  216.   si.ic_cmd = NIOCSTIME;
  217.   si.ic_timout = 10;
  218.   si.ic_len = sizeof timeout;
  219.   si.ic_dp = (char *)&timeout;
  220.   if (ioctl(s, I_STR, (char *)&si) < 0) {
  221.     perror("ioctl: timeout");
  222.     return(-1);
  223.   }
  224.   
  225.   si.ic_cmd = NIOCSCHUNK;
  226.   
  227.   si.ic_len = sizeof chunksize;
  228.   si.ic_dp = (char *)&chunksize;
  229.   if (ioctl(s, I_STR, (char *)&si)) {
  230.     perror("ioctl: chunk size");
  231.     return(-1);
  232.   }
  233. }
  234. #endif
  235.  
  236. /*
  237.  * establish protocol filter
  238.  *
  239. */
  240. private int
  241. setup_pf(s, prot)
  242. int s;
  243. u_short prot;
  244. {
  245.   u_short offset;
  246.   struct ether_header eh;
  247.   struct packetfilt pf;
  248.   register u_short *fwp = pf.Pf_Filter;
  249.   struct strioctl si;
  250. #define s_offset(structp, element) (&(((structp)0)->element))
  251.   offset = ((int)s_offset(struct ether_header *, ether_type))/sizeof(u_short);
  252.   *fwp++ = ENF_PUSHWORD + offset;
  253.   *fwp++ = ENF_PUSHLIT | ENF_EQ;
  254.   *fwp++ = htons(prot);
  255.   pf.Pf_FilterLen = 3;
  256.  
  257.   si.ic_cmd = NIOCSETF;
  258.   si.ic_timout = 10;
  259.   si.ic_len = sizeof(pf);
  260.   si.ic_dp = (char *)&pf;
  261.   if (ioctl(s, I_PUSH, "pf") < 0) {
  262.     perror("ioctl: push protocol filter");
  263.     return(-1);
  264.   }
  265.   if (ioctl(s, I_STR, (char *)&si) < 0) {
  266.     perror("ioctl: protocol filter");
  267.     return(-1);
  268.   }
  269.   return(0);
  270. }
  271.  
  272. export int
  273. pi_get_ethernet_address(edx,ea)
  274. int edx;
  275. u_char *ea;
  276. {
  277.   struct sockaddr *sa;
  278.   struct ephandle *eph;
  279.  
  280.   if (edx < 1 || edx > MAXOPENPROT || !ephlist[edx-1].inuse)
  281.     return(-1);
  282.   
  283.   eph = &ephlist[edx-1];
  284.   if (ioctl(eph->socket, SIOCGIFADDR, &eph->ifr) < 0) {
  285.     perror("ioctl: SIOCGIFADDR");
  286.     return(-1);
  287.   }
  288.   sa = (struct sockaddr *)eph->ifr.ifr_data;
  289.   bcopy(sa->sa_data, ea, 6);
  290.   return(0);
  291. }
  292.  
  293. export
  294. pi_listener(edx, listener, arg)
  295. int edx;
  296. int (*listener)();
  297. caddr_t arg;
  298. {
  299.   if (edx < 1 || edx > MAXOPENPROT || !ephlist[edx-1].inuse)
  300.     return(-1);
  301.  
  302.   fdlistener(ephlist[edx-1].socket, listener, arg, edx);
  303. }
  304.  
  305. /*
  306.  * cheat - iov[0] == struct etherheader
  307.  *
  308. */
  309. export int
  310. pi_readv(edx, iov, iovlen)
  311. int edx;
  312. struct iovec *iov;
  313. int iovlen;
  314. {
  315.   struct ephandle *eph ;
  316.   int cc;
  317.  
  318.   if (edx < 1 || edx > MAXOPENPROT)
  319.     return(-1);
  320.   eph = &ephlist[edx-1];
  321.   if (!eph->inuse)
  322.     return(-1);
  323.   if ((cc = readv(eph->socket, iov, iovlen)) < 0) {
  324.     perror("abread");
  325.     return(cc);
  326.   }
  327.   return(cc);
  328. }
  329.  
  330. export int
  331. pi_read(edx, buf, bufsiz)
  332. int edx;
  333. caddr_t buf;
  334. int bufsiz;
  335. {
  336.   struct iovec iov[2];
  337.   struct ethernet_addresses ea;
  338.   int cc;
  339.  
  340.   iov[0].iov_base = (caddr_t)&ea;
  341.   iov[0].iov_len = sizeof(ea);
  342.   iov[1].iov_base = (caddr_t)buf;
  343.   iov[1].iov_len = bufsiz;
  344.   cc = pi_readv(edx, iov, 2);
  345.   return(cc - sizeof(ea));
  346. }
  347.  
  348. export int
  349. pi_write(edx, buf, buflen, eaddr)
  350. int edx;
  351. caddr_t buf;
  352. int buflen;
  353. char *eaddr;
  354. {
  355.   struct ephandle *eph;
  356.   struct ether_header *eh;
  357.   struct strbuf pbuf, dbuf;
  358.   struct sockaddr sa;
  359.  
  360.   if (edx < 1 || edx > MAXOPENPROT || eaddr == NULL)
  361.     return(-1);
  362.  
  363.   eph = &ephlist[edx-1];
  364.   if (!eph->inuse)
  365.     return(-1);
  366.  
  367.   sa.sa_family = AF_UNSPEC;    /* by def. */
  368.   eh = (struct ether_header *)sa.sa_data;        /* make pointer */
  369.   bcopy(eaddr, &eh->ether_dhost, sizeof(eh->ether_dhost));
  370.   eh->ether_type = eph->protocol;
  371.   pbuf.len = sizeof(sa);
  372.   pbuf.buf = (char *)&sa;
  373.   dbuf.len = buflen;
  374.   dbuf.buf = (caddr_t)buf;
  375.  
  376.   if (putmsg(eph->socket, &pbuf, &dbuf, 0) < 0) {
  377.     return(-1);
  378.   }
  379.   return(buflen);
  380. }
  381.  
  382. private char ebuf[2000];    /* big enough */
  383.  
  384. export int
  385. pi_writev(edx, iov, iovlen, eaddr)
  386. int edx;
  387. struct iovec *iov;
  388. int iovlen;
  389. unsigned char eaddr[6];
  390. {
  391.   int i;
  392.   char *p;
  393.   int len;
  394.   
  395.   if (edx < 1 || edx > MAXOPENPROT || eaddr == NULL)
  396.     return(-1);
  397.   if (!ephlist[edx-1].inuse)
  398.     return(-1);
  399.  
  400.   for (len = 0, p = ebuf, i = 0 ; i < iovlen ; i++)
  401.     if (iov[i].iov_base && iov[i].iov_len >= 0) {
  402.       bcopy(iov[i].iov_base, p, iov[i].iov_len);
  403.       p += iov[i].iov_len;    /* advance */
  404.       len += iov[i].iov_len;    /* advance */
  405.     }
  406.   return(pi_write(edx, ebuf, len, eaddr));
  407. }
  408.